package com.atguigu.aiproject.websocket.handler;

import com.atguigu.aiproject.service.ChatService;
import com.atguigu.aiproject.websocket.entity.WebSocketMessage;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class ChatWebSocketHandler extends TextWebSocketHandler {

    @Autowired
    private ChatService chatService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate; // 改为Object类型

    @Autowired
    private ObjectMapper objectMapper;

    // 保存用户会话
    private static final Map<Integer, WebSocketSession> userSessions = new ConcurrentHashMap<>();

    private static final Logger log = LoggerFactory.getLogger(ChatWebSocketHandler.class);

    /**
     * 连接建立时自动执行，添加用户会话。
     * 是TextWebSocketHandler 类的生命周期方法之一，属于框架的标准行为
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        Integer userId = getUserIdFromSession(session);
        if (userId != null) {
            // 检查是否已存在连接，如果存在则关闭旧连接（单端登录）
            WebSocketSession existingSession = userSessions.get(userId);
            if (existingSession != null && existingSession.isOpen()) {
                try {
                    existingSession.close(CloseStatus.SESSION_NOT_RELIABLE);
                    log.info("关闭用户 {} 的旧 WebSocket 连接", userId);
                } catch (IOException e) {
                    log.error("关闭旧连接失败: {}", e.getMessage());
                }
            }

            userSessions.put(userId, session);
            // 更新用户在线状态
            chatService.updateUserOnlineStatus(userId, true);
            // 广播在线状态
            broadcastOnlineStatus(userId, true);

            log.info("用户 {} WebSocket 连接建立", userId);
        } else {
            log.warn("WebSocket 连接建立失败: 无法获取用户ID");
            try {
                session.close(CloseStatus.NOT_ACCEPTABLE);
            } catch (IOException e) {
                log.error("关闭连接失败: {}", e.getMessage());
            }
        }
    }
    /**
     * 处理文本消息
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        Integer userId = getUserIdFromSession(session);
        if (userId == null) {
            log.warn("处理消息时无法获取用户ID，关闭连接");
            try {
                session.close(CloseStatus.NOT_ACCEPTABLE);
            } catch (IOException e) {
                log.error("关闭连接失败: {}", e.getMessage());
            }
            return;
        }

        try {
            String payload = message.getPayload();
            WebSocketMessage wsMessage = objectMapper.readValue(payload, WebSocketMessage.class);

            // 验证消息接收者权限（可选，根据业务需求）
            if (!validateMessagePermission(userId, wsMessage)) {
                log.warn("用户 {} 无权限发送此消息", userId);
                sendErrorMessage(userId, "无权限执行此操作");
                return;
            }

            switch (wsMessage.getType()) {
                case "MESSAGE":
                    if (wsMessage.getMessage() != null) {
                        // 确保发送者ID正确
                        wsMessage.getMessage().setSenderId(userId);
                        chatService.sendMessage(wsMessage.getMessage());//发送消息
                    }
                    break;
                case "READ":
                    if (wsMessage.getReceiverId() != null) {
                        chatService.markMessagesAsRead(userId, wsMessage.getReceiverId());
                    }
                    break;
                case "TYPING":
                    if (wsMessage.getReceiverId() != null) {
                        handleTypingStatus(userId, wsMessage.getReceiverId(), true);
                    }
                    break;
                default:
                    log.warn("未知的WebSocket消息类型: {}", wsMessage.getType());
                    sendErrorMessage(userId, "未知的消息类型: " + wsMessage.getType());
            }
        } catch (JsonProcessingException e) {
            log.error("消息格式错误: {}", e.getMessage());
            sendErrorMessage(userId, "消息格式错误");
        } catch (Exception e) {
            log.error("处理消息时发生异常: {}", e.getMessage());
            sendErrorMessage(userId, "处理消息时发生错误");
        }
    }

    /**
     * 连接关闭时执行，移除用户会话
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        Integer userId = getUserIdFromSession(session);
        if (userId != null) {
            // 只移除当前会话，避免移除新连接
            WebSocketSession currentSession = userSessions.get(userId);
            if (currentSession == session) {
                userSessions.remove(userId);
                // 更新用户离线状态
                chatService.updateUserOnlineStatus(userId, false);
                // 广播离线状态
                broadcastOnlineStatus(userId, false);
                log.info("用户 {} WebSocket 连接关闭，状态: {}", userId, status);
            }
        }
    }

    /**
     * 处理传输错误
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        Integer userId = getUserIdFromSession(session);
        log.error("用户 {} WebSocket 传输错误: {}", userId, exception.getMessage());

        if (userId != null) {
            // 只移除当前会话
            WebSocketSession currentSession = userSessions.get(userId);
            if (currentSession == session) {
                userSessions.remove(userId);
                chatService.updateUserOnlineStatus(userId, false);
                broadcastOnlineStatus(userId, false);
            }
        }

        try {
            session.close(CloseStatus.SERVER_ERROR);
        } catch (IOException e) {
            log.error("关闭错误连接失败: {}", e.getMessage());
        }
    }

    // 发送消息给指定用户
    public void sendMessageToUser(Integer userId, WebSocketMessage message) {
        WebSocketSession session = userSessions.get(userId);
        if (session != null && session.isOpen()) {
            try {
                String jsonMessage = objectMapper.writeValueAsString(message);
                session.sendMessage(new TextMessage(jsonMessage));
                log.debug("消息发送成功: 用户 {}, 类型 {}", userId, message.getType());
            } catch (IOException e) {
                handleSendMessageFailure(userId, message, e);
            }
        } else {
            log.warn("用户 {} 不在线或会话不可用，无法发送消息", userId);
            // 可以在这里实现离线消息存储等逻辑
        }
    }

    // 广播在线状态
    private void broadcastOnlineStatus(Integer userId, boolean isOnline) {
        WebSocketMessage statusMessage = new WebSocketMessage();
        statusMessage.setType("ONLINE_STATUS");
        statusMessage.setSenderId(userId);
        statusMessage.setIsOnline(isOnline);
        statusMessage.setTimestamp(LocalDateTime.now());

        List<Integer> relatedUsers = getRelatedUsers(userId);
        for (Integer relatedUser : relatedUsers) {
            // 只发送给在线的相关用户
            if (userSessions.containsKey(relatedUser)) {
                sendMessageToUser(relatedUser, statusMessage);
            }
        }

        log.debug("广播用户 {} 在线状态: {}", userId, isOnline ? "在线" : "离线");
    }

    // 处理正在输入状态
    private void handleTypingStatus(Integer userId, Integer targetUserId, boolean isTyping) {
        WebSocketMessage typingMessage = new WebSocketMessage();
        typingMessage.setType("TYPING");
        typingMessage.setSenderId(userId);
        typingMessage.setReceiverId(targetUserId);
        typingMessage.setTimestamp(LocalDateTime.now());

        sendMessageToUser(targetUserId, typingMessage);//发送正在输入状态
        log.debug("用户 {} 正在输入通知发送给用户 {}", userId, targetUserId);
    }

    // 发送错误消息给客户端
    private void sendErrorMessage(Integer userId, String errorMessage) {
        WebSocketMessage errorMsg = new WebSocketMessage();
        errorMsg.setType("ERROR");
        errorMsg.setTimestamp(LocalDateTime.now());
        // 可以添加错误详情字段
        sendMessageToUser(userId, errorMsg);
    }

    // 验证消息权限
    private boolean validateMessagePermission(Integer userId, WebSocketMessage message) {
        // 根据业务需求实现权限验证
        // 例如：检查用户是否可以给目标用户发送消息等

        if ("MESSAGE".equals(message.getType()) && message.getMessage() != null) {
            Integer receiverId = message.getMessage().getReceiverId();
            // 简单的权限检查：不能给自己发消息
            return !userId.equals(receiverId);
            // 可以添加更多权限检查，如黑名单、好友关系等
        }

        return true;
    }
    /**
     * 获取用户ID从会话中
     */
    private Integer getUserIdFromSession(WebSocketSession session) {
        return (Integer) session.getAttributes().get("userId");
    }

    /**
     * 获取相关用户列表
     */
    private List<Integer> getRelatedUsers(Integer userId) {
        // 实现获取相关用户列表的逻辑
        // 例如：获取用户的好友、关注者等
        // 这里可以使用Redis缓存好友列表等

        try {
            // 从Redis获取用户的好友列表
            String friendsKey = "user:friends:" + userId;
            @SuppressWarnings("unchecked")
            List<Integer> friends = (List<Integer>) redisTemplate.opsForValue().get(friendsKey);
            if (friends != null) {
                return friends;
            }
        } catch (Exception e) {
            log.error("从Redis获取好友列表失败: {}", e.getMessage());
        }

        // 如果Redis不可用或没有数据，返回空列表
        return Collections.emptyList();
    }

    /**
     * 处理发送消息失败
     */
    private void handleSendMessageFailure(Integer userId, WebSocketMessage message, Exception e) {
        log.error("发送消息给用户 {} 失败: {}", userId, e.getMessage());

        // 可以根据错误类型采取不同措施
        if (e instanceof IOException) {
            // 网络错误，可以尝试重试或标记用户离线
            WebSocketSession session = userSessions.get(userId);
            if (session != null && !session.isOpen()) {
                userSessions.remove(userId);
                chatService.updateUserOnlineStatus(userId, false);
                log.info("因发送失败移除用户 {} 的会话", userId);
            }
        }

        // 可以记录到数据库或发送到消息队列进行后续处理
    }

    /**
     * 获取所有在线用户ID
     */
    public List<Integer> getOnlineUsers() {
        return new ArrayList<>(userSessions.keySet());
    }

    /**
     * 检查用户是否在线
     */
    public boolean isUserOnline(Integer userId) {
        WebSocketSession session = userSessions.get(userId);
        return session != null && session.isOpen();
    }

    /**
     * 强制断开用户连接（用于管理员操作等）
     */
    public void disconnectUser(Integer userId) {
        WebSocketSession session = userSessions.get(userId);
        if (session != null && session.isOpen()) {
            try {
                session.close(CloseStatus.NORMAL);
                userSessions.remove(userId);
                chatService.updateUserOnlineStatus(userId, false);
                log.info("强制断开用户 {} 的连接", userId);
            } catch (IOException e) {
                log.error("强制断开用户连接失败: {}", e.getMessage());
            }
        }
    }
}